package ar.com.msebuilder;

import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;

import org.tmatesoft.svn.core.SVNException;
import org.tmatesoft.svn.core.SVNLogEntry;
import org.tmatesoft.svn.core.io.SVNRepository;
import org.tmatesoft.svn.core.wc.SVNRevision;

public class SVNRevisionsFilter {

	public enum SVNRevFilterTypes {
		REVISIONS, DAILY, WEEKLY, MONTHLY;
	}
	
	private long minRevision;
	private long maxRevision;
	private SVNRepository svnRepository;
	
	
	public SVNRevisionsFilter(SVNRepository svnRepository, long minRevision, 
			long maxRevision) {
		this.svnRepository = svnRepository;
		this.minRevision = minRevision;
		this.maxRevision = maxRevision;
	}
	
	public LinkedList<SVNRevision> parseRevisionsList(SVNRevFilterTypes revFilterType) {
		LinkedList<SVNRevision> svnRevisions = new LinkedList<SVNRevision>();
		switch(revFilterType) {
			case REVISIONS:
				svnRevisions = parseRevisionsByNum();
				break;
			case DAILY: case WEEKLY: case MONTHLY:
				svnRevisions = parseRevisionsByDate(revFilterType);
				break;				
		}
		return svnRevisions;
	}
	
	private LinkedList<SVNRevision> parseRevisionsByNum() {
		LinkedList<SVNRevision> svnRevisions = new LinkedList<SVNRevision>();
		for (long rev=minRevision; rev<=maxRevision; rev++) {
			svnRevisions.add(SVNRevision.create(rev));
		}
		return svnRevisions;
	}
	
	private LinkedList<SVNRevision> parseRevisionsByDate(SVNRevFilterTypes revFilterType) {
		LinkedList<SVNRevision> svnResultRevisions = new LinkedList<SVNRevision>();
		// Keeps the last revision for the current date been processed on every loop
		SVNRevision lastRevForDate = null;
	    try {
	    	Collection<SVNLogEntry> logEntries = svnRepository.log(new String[] {""} , 
	    			null, minRevision, maxRevision, true, true);
	            Calendar lastCal = null;
	            Calendar currentCal = null;
	            for (Iterator<SVNLogEntry> entries = logEntries.iterator(); entries.hasNext();) {
	                SVNLogEntry logEntry = entries.next();
	                // If it's the first loop
	                if (lastCal == null){
	                    lastCal = Calendar.getInstance();
	                    lastCal.setTime(logEntry.getDate());
	                    currentCal = Calendar.getInstance();
	                    lastRevForDate = SVNRevision.create(logEntry.getRevision());
//	                    currentCal.setTime(logEntry.getDate());
	                } else {
	                	Date logEntryDate = logEntry.getDate();
                		// If for some reason the date in the log entry is null
                		// proceed as if this entry belongs to the same date currently
	                	// been processed 
	                	if (logEntryDate == null || 
	                    	isEqual(logEntryDate, lastCal, revFilterType)){
	                    	// Overwrite the last revision for this date
	                    	lastRevForDate = SVNRevision.create(logEntry.getRevision());
	                    } else {
	                    	currentCal.setTime(logEntryDate);
	                    	// When an entry of a different date is found, the last one
	                    	// of the previous date is added to the result
	                    	svnResultRevisions.add(lastRevForDate);
	                    	// The new log entry becomes the last of the new date
	                    	lastRevForDate = SVNRevision.create(logEntry.getRevision());
	                    	lastCal = (Calendar) currentCal.clone();	                    	
	                    }	                		
	                }
	            }
	            // If the revision in lastRevForDate is not the same as the last 
	            // revision added svnResultRevisions, add lastRevForDate in it
	            if (!svnResultRevisions.get(svnResultRevisions.size()-1).
	            		equals(lastRevForDate)) {
                	svnResultRevisions.add(lastRevForDate);
	            }
	        } catch (SVNException e) {
	            e.printStackTrace();
	        }
	        return svnResultRevisions;
	    }
	    
	private boolean isEqual(Date revDate1, Calendar revCal2, 
			SVNRevFilterTypes revFilterType) {
		Calendar revCal1 = Calendar.getInstance();
		revCal1.setTime(revDate1);
		switch(revFilterType) {
	    	case DAILY:
	    		return (revCal1.get(Calendar.DATE) == revCal2.get(Calendar.DATE));
	    	case WEEKLY:
	    		return (revCal1.get(Calendar.WEEK_OF_YEAR) == revCal2.get(Calendar.WEEK_OF_YEAR));
	    	case MONTHLY:
	    		return (revCal1.get(Calendar.MONTH) == revCal2.get(Calendar.MONTH) && (revCal1.get(Calendar.YEAR) == revCal2.get(Calendar.YEAR)));
		}
	    return false;
	}	
	
}
